package com.agrm.rabc.service.impl;


import com.agrm.model.rabc.dto.Menu;
import com.agrm.rabc.mapper.MenuDao;
import com.agrm.rabc.service.MenuService;
import com.agrm.utils.TreeUtils;
import com.agrm.utils.XinUtils;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@CacheConfig(cacheNames = "shoplook2025-menu")
@Service
public class MenuServiceImpl implements MenuService {
    private MenuDao menuDao;

    @Autowired
    public void setMenuDao(MenuDao menuDao) {
        this.menuDao = menuDao;
    }

    @Cacheable(key = "'all'")
    @Override
    public List<Menu> findAll() {
        return menuDao.selectList(null);
    }

    @Cacheable(key = "'tree'")
    @Override
    public List<Menu> findTree() {
        List<Menu> menus = self().findAll();
        return TreeUtils.buildTree(menus);
    }

    @Cacheable(key = "#id")
    @Override
    public Menu findById(Integer id) {
        List<Menu> roots = self().findTree();
        return TreeUtils.findById(roots, id);
    }

    @CacheEvict(allEntries = true)
    @Override
    public boolean save(Menu menu) {
        return menuDao.insert(menu) == 1;
    }

    @CacheEvict(allEntries = true)
    @Override
    public boolean update(Menu menu) {
        return menuDao.updateById(menu) == 1;
    }

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    @CacheEvict(allEntries = true)
    @Override
    public int deleteByIds(List<Integer> ids) {
        @Getter
        @Setter
        @AllArgsConstructor
        class Ref {
            private int count;

            private void inc(int delta) {
                count += delta;
            }

            private void inc() {
                inc(1);
            }
        }

        Ref ref = new Ref(0);
        ids.forEach(it -> {
            Menu menu = self().findById(it);
            if (menu != null) {
                if (XinUtils.isNotEmpty(menu.getChildren())) {
                    List<Integer> childrenIds = menu.getChildren().stream().map(Menu::getId).toList();
                    //此处其实无需触发aop，仅最外层触发aop即可
                    int count = deleteByIds(childrenIds);
                    ref.inc(count);
                }
                //删除自身
                menuDao.deleteById(it);
                ref.inc();
            }
        });
        return ref.getCount();
    }

    private MenuService self() {
        return (MenuService) AopContext.currentProxy();
    }
}
